<?php

namespace app\api\model\xyvenue\order;
use app\api\model\xyvenue\user\User;
use app\api\model\xyvenue\order\Item as OrderItem;
use app\api\model\xyvenue\store\Store as StoreModel;
use app\api\model\xyvenue\Level as LevelModel;
use app\api\model\xyvenue\Venue as VenueModel;
use app\api\model\xyvenue\Package as PackageModel;
use app\api\model\xyvenue\Config as ConfigModel;
use app\api\model\xyvenue\refund\Log as RefundLog;
use addons\xyvenue\service\PayService;
use addons\xyvenue\exception\Exception;
use app\api\model\xyvenue\user\Coupon as UserCouponModel;
use think\Model;
use think\Db;
use think\Queue;

class Order extends Model
{

    // 表名
    protected $name = 'xyvenue_order';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'integer';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    protected $deleteTime = false;

    // 追加属性
    protected $append = [
        'paytime_text',
        'status_text',
        'ext_arr'
    ];

    public function getExtArrAttr($value, $data)
    {
        $ext = (isset($data['ext']) && $data['ext']) ? json_decode($data['ext'], true) : [];
        return $ext;
    }

    //使用优惠券
    public static function useCoupon($params){

        $user = User::info();
        extract($params);
        $order = self::with(['item'])->where(['user_id'=>$user->id,'id'=>$order_id])->find();
        if (!$order) {
            new Exception('订单不存在');
        }
        if($order['status'] != 0){
            new Exception('订单状态错误');
        }

        $userCoupon = UserCouponModel::where(['user_id'=>$user->id,'id'=>$user_coupon_id])->find();
        if(empty($userCoupon)){
            new Exception('优惠券不存在');
        }

        if($order['total_amount'] < $userCoupon['atleast']){
            new Exception('满'.$userCoupon['atleast'].'元才能使用');
        }

        if($order['user_coupon_id'] != 0){
            $oldUserCoupon = UserCouponModel::get($order['user_coupon_id']);
            if(!empty($oldUserCoupon)){
                $oldUserCoupon->status = 0;
                $oldUserCoupon->usetime = 0;
                $oldUserCoupon->useorderid = 0;
                $oldUserCoupon->useordertype = '';
                $oldUserCoupon->save();
            }
        }
    
        $userCoupon->status = 1;
        $userCoupon->usetime = time();
        $userCoupon->useorderid = $order['id'];
        $userCoupon->useordertype = 'type';
        $userCoupon->save();

        $couponFee = $userCoupon['money'];

        if($userCoupon['type'] == 'discount'){
            $couponFee = bcdiv($order['total_amount']*(10-$userCoupon['discount']),10,2);
        }

        $order->user_coupon_id = $userCoupon['id'];
        $order->coupon_fee = $couponFee;
        $order->total_fee = bcsub($order['total_amount'],$couponFee,2);
        $order->save();

        return $order;
    }

    //订单支付加载数据
    public static function getInitData($params){

        $user = User::info();
        extract($params);
        $order = self::with(['item'])->where(['user_id'=>$user->id,'id'=>$order_id])->find();
        if (!$order) {
            new Exception('订单不存在');
        }
        if($order['status'] != 0){
            new Exception('订单状态错误');
        }
        return $order;
    }

    public function setExt($order, $field, $origin = [])
    {
        $newExt = array_merge($origin, $field);

        $orderExt = $order['ext_arr'];

        return array_merge($orderExt, $newExt);
    }

    // 订单详情
    public static function getDetail($params)
    {
        $user = User::info();
        extract($params);

        $order = self::with(['item'])->where('user_id', $user->id);

        if (isset($order_sn)) {
            $order = $order->where('order_sn', $order_sn);
        }
        if (isset($id)) {
            $order = $order->where('id', $id);
        }

        $order = $order->find();

        if (!$order) {
            new Exception('订单不存在');
        }

        return $order;
    }

    // 取消订单
    public static function cancelOrder($params)
    {
        $user = User::info();
        extract($params);
        $order = self::where(['user_id'=>$user->id,'id'=>$id,'status'=>0])->find($id);
        if (!$order) {
            new Exception('订单不存在或已取消');
        }

        return Db::transaction(function () use ($user,$order) {

            $order->status = -1;        // 取消订单
            $order->ext = json_encode($order->setExt($order, ['cancel_time' => time()]));      // 取消时间
            $order->save();

            //返还订单使用的优惠券
            if($order['user_coupon_id'] != 0){
                $oldUserCoupon = UserCouponModel::get($order['user_coupon_id']);
                if(!empty($oldUserCoupon)){
                    $oldUserCoupon->status = 0;
                    $oldUserCoupon->usetime = 0;
                    $oldUserCoupon->useorderid = 0;
                    $oldUserCoupon->useordertype = '';
                    $oldUserCoupon->save();
                }

                $order->user_coupon_id = 0;
                $order->coupon_fee = 0;
                $order->total_fee = $order['total_amount'];
                $order->save();
            }

            //更新预定场地状态
            $orderItem = OrderItem::where(['order_id'=>$order['id']])->select();
            foreach($orderItem as $oi){
                $oi->status = -1;
                $oi->save();
            }

            return true;

        });

    }

    // 退订
    public static function refundOrder($params)
    {
        $user = User::info();
        extract($params);

        $order = self::where(['user_id'=>$user->id,'id'=>$id,'status'=>1])->find();
        if(!$order) {
            new Exception('订单状态错误，不能退订。');
        }

        //提前退订时间配置
        $xyvenueConfig = ConfigModel::getValueByName('xyvenue');
        $returnhour = intval(isset($xyvenueConfig['returnhour']) ? $xyvenueConfig['returnhour'] : 24);


        if(time() + $returnhour * 3600 > strtotime($order['date'])){
            new Exception('到订单预定日期超过'.$returnhour.'小时的订单才能退订。');
        }

        return Db::transaction(function () use ($user,$order) {

            // 生成退款单
            $refundLog = new RefundLog();
            $refundLog->order_sn = $order->order_sn;
            $refundLog->refund_sn = xyvenueCreateOrderNo();
            $refundLog->order_id = $order->id;
            $refundLog->pay_fee = $order->pay_fee;
            $refundLog->refund_fee = $order->pay_fee;
            $refundLog->pay_type = $order->pay_type;
            $refundLog->save();

            //余额支付退款
            if($order['pay_type'] == 'balance'){
                User::money($order['pay_fee'],$user->id,'return_order',$order['id']);
                
            }else if($order['pay_type'] == 'wechat'){ //微信支付退款


                $total_fee = $order->pay_fee * 100;

                $order_data = [
                    'out_trade_no' => $order->order_sn,
                    'out_refund_no' => $refundLog->refund_sn,
                    'total_fee' => $total_fee,
                    'refund_fee' => $total_fee,
                    'refund_desc' => '退订',
                ];

                $notify_url = request()->domain() . '/api/xyvenue/pay/notifyr/payment/' . $order->pay_type . '/platform/' . $order->platform.'/order_type/order';
                $pay = new PayService($order->pay_type, $order->platform, $notify_url);
                $pay->refund($order_data);
            }

            //先改为成功状态，不管回调。
            self::refundFinish($order,$refundLog);

            return true;
        });
    }

    //退款完成
    public static function refundFinish($order, $refundLog)
    {
        $refundLog->status = 1;
        $refundLog->save();

        $order->status = -3;
        $order->save();

        OrderItem::where(['order_id'=>$order->id])->update(['status'=>-3]);
    }

    /**
     * 创建订单
     */
    public static function addOrder($params)
    {
        $user = User::info();
        extract($params);
        //场馆
        $storeInfo = StoreModel::getDetail($store_id);

        if(empty($storeInfo)){
            new Exception('场馆不存在！');
        }

        //场地
        $venueInfo = VenueModel::getDetail($venue_id);
        if(empty($storeInfo)){
            new Exception('场地不存在！');
        }

        //提前天数
        $advancedays = $storeInfo['advancedays'];

        //预定小时
        $dayhour = $storeInfo['dayhour'];

        //会员等级
        if($user->xyvenue_level_id > 0){
            $userLevel = LevelModel::where(['id'=>$user->xyvenue_level_id,'status'=>'normal'])->find();
            if(!empty($userLevel)){
                $advancedays = $userLevel['advancedays'];
                $dayhour = $userLevel['dayhour'];
            }
        }

        // 检测buy_item
        $areaList = $venueInfo['area'];
        $totalAmount = 0; //订单总金额

        $duration = bcdiv($venueInfo['duration'] * count($buy_item),60,2); //订单总时长
        foreach ($buy_item as $item) {

            //检测预定日期
            if(xyvenueCountDays($buy_date) > $advancedays){
                if($advancedays){
                    new Exception('您只能提前'.$advancedays.'天预定');
                }else{
                    new Exception('您只能当天预定');
                }
            }

            //检测每天可预定小时
            if($duration > $dayhour){
                new Exception('您每天只能预定'.$dayhour.'小时');
            }else{
                //查询已预定时长
                $od = self::where(['date'=>$buy_date,'user_id'=>$user->id,'store_id'=>$storeInfo->id,'status'=>['in',[0,1,2]]])->sum('duration');
                if(bcadd($od,$duration,2) > $dayhour ){
                    new Exception('您已预定'.$od.'小时,还能预定'.bcsub($dayhour,$od,2).'小时');
                }
            }
           
            //检测下单区域是否存在
            $flag = false;
            foreach($areaList as $al){
                if($item['area'] == $al['name']){
                    $flag = true;
                }
            }
            if(!$flag){
                new Exception('场地区域不存在！');
            }

            //检测区域时段是否已预定
            $isYd = OrderItem::where([
                    'date'=>$buy_date,
                    'store_id'=>$storeInfo->id,
                    'venue_id'=>$venueInfo->id,
                    'area'=>$item['area'],
                    'starttime'=>$item['startTime'],
                    'endtime'=>$item['endTime'],
                    'status'=>['in',[0,1,2]
                ]
            ])->find();
            if($isYd){
                new Exception($item['area'].$buy_date.' '.$item['startTime'].'-'.$item['endTime'].'已被预定');
            }else{
                //检测是否已包场
                $isYd = PackageModel::where([
                    'startdate'=>['<=',$buy_date],
                    'enddate'=>['>=',$buy_date],
                    'store_id'=>$storeInfo->id,
                    'venue_id'=>$venueInfo->id,
                    'arealist'=>['like','%'.$item['area'].'%'],
                    'timelist'=>['like','%'.$item['startTime'].'-'.$item['endTime'].'%'],
                ])->find();
            }
            
            $totalAmount = bcadd($item['price'], $totalAmount, 2);

        }
        $close_time = 5;
        $order = Db::transaction(function () use ($user,$storeInfo,$venueInfo,$totalAmount,$buy_item,$buy_date,$duration,$close_time) {
            
            $orderData = [];
            $orderData['order_sn'] = xyvenueCreateOrderNo();
            $orderData['store_id'] = $storeInfo->id;
            $orderData['venue_id'] = $venueInfo->id;
            $orderData['user_id'] = $user->id;
            $orderData['date'] = $buy_date;
            $orderData['duration'] = $duration;
            $orderData['storename'] = $storeInfo->name;
            $orderData['storelogo'] = $storeInfo->logo;
            $orderData['venuename'] = $venueInfo->name;
            $orderData['total_amount'] = $totalAmount;
            $orderData['total_fee'] = $totalAmount;
            $orderData['ext'] = json_encode(['expired_time' => time() + ($close_time * 60)]);
            $order = new Order();
            $order->allowField(true)->save($orderData);

            // 添加订单选项
            foreach ($buy_item as $buyinfo) {
                $orderItem = new OrderItem();
                $orderItem->order_id = $order->id;
                $orderItem->store_id = $storeInfo->id;
                $orderItem->venue_id = $venueInfo->id;
                $orderItem->user_id = $user->id;
                $orderItem->date = $buy_date;
                $orderItem->week = xyvenueGetWeek($buy_date);
                $orderItem->area = $buyinfo['area'];
                $orderItem->starttime = $buyinfo['startTime'];
                $orderItem->endtime = $buyinfo['endTime'];
                $orderItem->price = $buyinfo['price'];
                $orderItem->save();
            }

            return $order;
        });

        //订单关闭队列
        Queue::later(($close_time * 60), '\addons\xyvenue\service\QueueOrder@autoClose', ['order' => $order,'type'=>'order'], 'XYvenue');

        return $order;
    }

    public static function getLists($params)
    {
        extract($params);
        $user = User::info();
        $where = ['user_id'=>$user->id];
        if($status != 'all'){
            $where['status'] = $status;
        }
        $list = self::with(['item'])->where($where)->order('id desc')->paginate();

        return $list;
    }


    /**
     * 订单支付成功
     *
     * @param [type] $order
     * @param [type] $notify
     * @return void
     */
    public function paySuccess($order, $notify)
    {

        $order->status = 1;
        $order->paytime = time();
        $order->transaction_id = $notify['transaction_id'];
        $order->payment_json = $notify['payment_json'];
        $order->pay_type = $notify['pay_type'];
        $order->pay_fee = $notify['pay_fee'];
        $order->save();

        //更新预定场地状态
        $orderItem = OrderItem::where(['order_id'=>$order['id']])->select();
        foreach($orderItem as $oi){
            $oi->status = 1;
            $oi->save();
        }

        //增加用户消费金额
        $user = User::get($order->user_id);
        $user->setInc('xyvenue_consume',$order->total_fee);

        // 支付后监听
        $params = ['order'=>$order,'type'=>'order'];
        \think\Hook::listen('xyvenue_order_payed_after', $params);
        
        return $order;
    }

    
    public function getStatusList()
    {
        return ['-3' => __('已退订'),'-2' => __('已关闭'), '-1' => __('已取消'), '0' => __('待支付'), '1' => __('已支付')];
    }


    public function getPaytimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['paytime']) ? $data['paytime'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
        $list = $this->getStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }

    protected function setPaytimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    public function item()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id');
    }


}
